﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.Networking.BackgroundTransfer;
using Windows.Storage;
using Windows.Foundation;

namespace SimpleImageCacherRT
{
    public sealed class SimpleImageCacher
    {
        private static SimpleImageCacher _instance = new SimpleImageCacher();
	    public static SimpleImageCacher Instance {
		    get {
			    return _instance;
		    }
	    }
	    private static readonly int LibVersion = 1;
	    private static readonly string CacheDirectoryName = "_simplecacher";
	    private static readonly string ContainerKey = "SimpleCacher";
	    private static readonly string HashesKey = "Files";
	    private static readonly string MiscKey = "Misc";
	    private static readonly string VersionKey = "Version";
        private static readonly string ClearFlagKey = "ClearFlag";
	
	    private ApplicationDataContainer Hash;
	    private StorageFolder CacheDir;
	
	    internal async Task _InitAsync()
        {
		    var localSettings = ApplicationData.Current.LocalSettings;
            var localFolder = ApplicationData.Current.LocalFolder;
            if (localSettings.Containers.ContainsKey(ContainerKey) && localSettings.Containers[ContainerKey].Containers.ContainsKey(MiscKey) && localSettings.Containers[ContainerKey].Containers[MiscKey].Values.ContainsKey(ClearFlagKey))
            {
                bool clearFlag = (bool)localSettings.Containers[ContainerKey].Containers[MiscKey].Values[ClearFlagKey];
                if(clearFlag){
                    try
                    {
                        var dir = await localFolder.GetFolderAsync(CacheDirectoryName);
                        await dir.DeleteAsync(StorageDeleteOption.Default);
                    }
                    catch (Exception)
                    {
                        System.Diagnostics.Debug.WriteLine("Cache Directory not found.");
                    }
                    try
                    {
                        localSettings.DeleteContainer(ContainerKey);
                    }
                    catch(Exception)
                    {
                        System.Diagnostics.Debug.WriteLine("Cache Hash Table not found.");
                    }
                }
            }
		    if (!localSettings.Containers.ContainsKey(ContainerKey))
		    {
			    localSettings.CreateContainer(ContainerKey, ApplicationDataCreateDisposition.Always);
			    localSettings.Containers[ContainerKey].CreateContainer(HashesKey, ApplicationDataCreateDisposition.Always);
			    localSettings.Containers[ContainerKey].CreateContainer(MiscKey, ApplicationDataCreateDisposition.Always);
			    localSettings.Containers[ContainerKey].Containers[MiscKey].Values[VersionKey] = LibVersion;
                localSettings.Containers[ContainerKey].Containers[MiscKey].Values[ClearFlagKey] = false;
		    }
		    this.Hash = localSettings.Containers[ContainerKey].Containers[HashesKey];

		    this.CacheDir = await localFolder.CreateFolderAsync(CacheDirectoryName, CreationCollisionOption.OpenIfExists);
		
		    IReadOnlyList<DownloadOperation> downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
		    if(downloads.Count > 0)
		    {
			    List<Task> tasks = new List<Task>();
			    foreach (DownloadOperation download in downloads)
			    {
				    tasks.Add(HandleDownloadAsync(download, false));
			    }
                await Task.WhenAll(tasks);
		    }
	    }

        public IAsyncAction InitAsync(){
            Task initializerTask = this._InitAsync();
            return initializerTask.AsAsyncAction();
        }

        public string GetImageURLString(string urlString)
        {
            return this.GetImageURLString(new Uri(urlString));
        }

        private string GetImageURLString(Uri uri)
        {
            string absoluteSourcePath = uri.AbsoluteUri;
            if (Hash.Values.ContainsKey(absoluteSourcePath))
            {
                return Hash.Values[absoluteSourcePath] as string;
            }
            StartCaching(uri);
            return absoluteSourcePath;
        }

        private async void StartCaching(Uri uri)
        {
            StorageFile destinationFile = await this.CacheDir.CreateFileAsync(CommonMethods.ComputeMD5(uri.AbsoluteUri), CreationCollisionOption.ReplaceExisting);
            BackgroundDownloader downloader = new BackgroundDownloader();
            DownloadOperation download = downloader.CreateDownload(uri, destinationFile);
            await HandleDownloadAsync(download, true);
        }

        private async Task HandleDownloadAsync(DownloadOperation download, bool start)
        {
            if (start)
            {
                await download.StartAsync();
            }
            else
            {
                await download.AttachAsync();
            }

            IStorageFile resultFile = download.ResultFile;
            Uri uri = download.RequestedUri;
            Hash.Values[uri.AbsoluteUri] = String.Join("/", "ms-appdata:///local", CacheDirectoryName, resultFile.Name);
        }

        public void SetClearFlag()
        {
            var localSettings = ApplicationData.Current.LocalSettings;
            localSettings.Containers[ContainerKey].Containers[MiscKey].Values[ClearFlagKey] = true;
        }
    }
}
